package string;

/**
 * String是不变对象-对象创建后内容不可改变
 * JVM对字符串有一个优化：常量池，它存在于堆中
 * Java推荐我们使用字面量创建字符串对象，并且会将其缓存在常量池中，当我们再次使用该字面量创建字符串时
 * Java会先从常量池中找有没有已经创建好的一样的地址，如果有，会重用对象地址减少内存的不必要开销
 */

public class StringDemo {
    public static void main(java.lang.String[] args){
        java.lang.String s1="123abc";//s1对象在栈内存中缓存了字面量为123abc的地址值
        java.lang.String s2="123abc";//相同字面量，系统在常量池中找到了一样的地址，s2重用了s1的地址
        System.out.println("s1="+s1);
        System.out.println("s2="+s2);
        System.out.println(s1==s1);//结果为true，地址相同，说明了s2使用了s1的对象

        java.lang.String s3=new java.lang.String("123abc");//new一定产生新的对象
        System.out.println("s3="+s3);
        System.out.println(s1==s3);//false

        /**
         * int t=864000000;     //  我们不知道这个数字是什么意思
         * int t=60*60*24*1000; //  这个写法更清晰的突出表达式的含义，增加可读性！
           一般我们会把结果写成表达式形式，这样会更直观，更容易懂得含义
           实际上t所存储的值就是864000000，这触发了编译器的预计算特性！

         * 编译器的预计算特性：当编译器编译代码时发现一个计算表达式计算符两侧都是直接量时会
           直接进行计算，并将结果替换成该表达式。
           注意：表达式并不会占用过多资源，虽然以后程序会运行多次，但是编译只进行一次，在
                运行之前，表达式已经被编译预计算成一个值了，即864000000

         * String s4="123"+"abc";字符串拼接是一种计算，启动了编译器的预编译机制
         * 会被编译器改变为：
         * String s4="123abc";
         */
        java.lang.String s4="123"+"abc";//字符串拼接，拼接内容产生新对象，但触发了编译器预编译机制
        System.out.println("s4="+s4);
        System.out.println(s1==s4);//true
        //这里，s4经过编译器预编译，已经是123abc了，所以和s1的地址是一样的

        java.lang.String s="123";//并不会出发预计算特性，因为一侧为变量(s)，一侧是直接量(123)；
        java.lang.String s5=s+"abc";//字符串拼接，拼接内容产生新对象
        System.out.println("s5="+s5);
        System.out.println(s1==s5);//false

        //String是不变对象-对象创建后内容不可改变,
        s2="123abc!";//改变了s2，但是s1不会变，改变s2只能在堆内存中重新分配一个内存
        System.out.println("s1="+s1);
        System.out.println("s2="+s2);
        System.out.println(s1=s2);//false
    }
}
